package com.yuhuihui.common.utils;

import com.yuhuihui.common.exception.IoCommonException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * 文件工具类
 *
 * @author yuhh
 * @date 2023-05-25 14:11:12
 */
public final class FileUtil {

    /** logger */
    private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);

    /**
     * 字符串转文件
     *
     * @param res      需要转的字符串
     * @param filePath 输出的文件地址
     * @return boolean
     * @author yuhh
     * @date 2023-05-25 14:11:18
     */
    public static boolean string2File(String res, String filePath) {
        File distFile =  new File(filePath);
        if(!distFile.getParentFile().exists()){
            boolean parent = distFile.getParentFile().mkdirs();
            if (!parent){
                return false;
            }
        }
        try(BufferedReader bufferedReader = new BufferedReader(new StringReader(res));
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(distFile))){
            // 字符缓冲区
            char[] buf = new char[1024];
            int len;
            while ((len = bufferedReader.read(buf)) != -1) {
                bufferedWriter.write(buf, 0, len);
            }
            bufferedWriter.flush();
        } catch (IOException e) {
            logger.info(res);
            logger.error("字符串转文件出现异常！", e);
            return false;
        }
        return true;
    }

    /**
     * 移动文件
     *
     * @param sourcePath 源文件路径（不包含文件名）
     * @param targetPath 目标文件路径（不包含文件名）
     * @param fileName   需要移动的文件名
     * @return boolean true：移动成功；false：移动失败
     * @author yuhh
     * @date 2023-05-25 14:11:24
     */
    public static boolean move(String sourcePath, String targetPath, String fileName) {
        String sourceFilePath = sourcePath + "\\" + fileName;
        String targetFilePath = targetPath + "\\" + fileName;
        File sourceFile = new File(sourceFilePath);
        File targetFile = new File(targetFilePath);
        if (!sourceFile.exists() || !sourceFile.isFile()){
            logger.info("{}文件不存在", sourceFilePath);
            return false;
        }
        // 如果父目录不存在。则创建父目录
        if(!targetFile.getParentFile().exists()){
            boolean parent = targetFile.getParentFile().mkdirs();
            if (!parent){
                logger.info("{}目录创建失败", targetFile.getParentFile());
                return false;
            }
        }
        // 创建源文件的输入流和目标文件的输出流
        try (InputStream is = Files.newInputStream(Paths.get(sourceFilePath));
             FileOutputStream os = new FileOutputStream(targetFilePath)) {
            byte[] bytes = new byte[1024 * 8];
            int len;
            //循环读取数据
            while ((len = is.read(bytes)) != -1) {
                os.write(bytes, 0, len);
            }
            return true;
        } catch (Exception e) {
            logger.error("把{}从{}移动到{}出现异常", fileName, sourcePath, targetPath, e);
            return false;
        }
    }

    /**
     * 输入流转文件
     *
     * @param res      输入流
     * @param filePath 输出的文件地址
     * @return boolean true：成功；false：失败
     * @author yuhh
     * @date 2023-05-25 14:11:31
     */
    public static boolean stream2File(InputStream res, String filePath) {
        return stream2File(res, new File(filePath));
    }

    /**
     * 输入流转文件
     *
     * @param res      输入流
     * @param distFile 文件信息
     * @return boolean
     * @author yuhh
     * @date 2024-01-24 17:38:12
     */
    public static boolean stream2File(InputStream res, File distFile) {
        if(!distFile.getParentFile().exists()){
            boolean parent = distFile.getParentFile().mkdirs();
            if (!parent){
                return false;
            }
        }
        try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(res));
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(distFile))){
            // 字符缓冲区
            char[] buf = new char[1024];
            int len;
            while ((len = bufferedReader.read(buf)) != -1) {
                bufferedWriter.write(buf, 0, len);
            }
            bufferedWriter.flush();
        } catch (IOException e) {
            logger.error("输入流转文件出现异常！", e);
            return false;
        }
        return true;
    }

    /**
     * 根据文件路局读取文件所有数据，返回字符串
     * 文件的长度不能超过Integer.MAX_VALUE
     *
     * @param filePath 文件路径
     * @return {@link String } 文件内容
     * @author yuhh
     * @date 2023-05-25 14:11:45
     */
    public static String readString(String filePath) {
        return readString(filePath, CharsetUtil.defaultCharset());
    }

    /**
     * 根据文件路局读取文件所有数据，并指定返回字符串的编码格式
     * 文件的长度不能超过Integer.MAX_VALUE
     *
     * @param filePath 文件路径
     * @param charset  编码格式
     * @return {@link String } 文件内容
     * @author yuhh
     * @date 2023-05-25 14:11:50
     */
    public static String readString(String filePath, Charset charset) {
        return readString(new File(filePath), charset);
    }

    /**
     * 读取文件所有数据，返回字符串
     * 文件的长度不能超过Integer.MAX_VALUE
     *
     * @param file 需要读取的文件
     * @return {@link String } 文件内容
     * @author yuhh
     * @date 2023-05-25 14:11:55
     */
    public static String readString(File file) {
        return readString(file, CharsetUtil.defaultCharset());
    }

    /**
     * 读取文件所有数据，并指定返回字符串的编码格式
     * 文件的长度不能超过Integer.MAX_VALUE
     *
     * @param file    需要读取的文件
     * @param charset 编码格式
     * @return {@link String } 文件内容
     * @author yuhh
     * @date 2023-05-25 14:11:59
     */
    public static String readString(File file, Charset charset) {
        return new String(readBytes(file), charset);
    }

    /**
     * 根据文件路局读取文件所有数据，返回byte数组
     * 文件的长度不能超过Integer.MAX_VALUE
     *
     * @param filePath 文件路径
     * @return {@link byte[] } 字节码
     * @author yuhh
     * @date 2023-05-25 14:12:05
     */
    public static byte[] readBytes(String filePath) {
        return readBytes(new File(filePath));
    }

    /**
     * 读取文件所有数据，返回byte数组
     * 文件的长度不能超过Integer.MAX_VALUE
     *
     * @param file 需要读取的文件
     * @return {@link byte[] } 字节码
     * @author yuhh
     * @date 2023-05-25 14:12:11
     */
    public static byte[] readBytes(File file) {
        long len = file.length();
        if (len >= Integer.MAX_VALUE) {
            throw new IoCommonException("文件大于最大数组大小");
        }

        byte[] bytes = new byte[(int) len];
        int readLength;
        try(FileInputStream input = new FileInputStream(file)) {
            readLength = input.read(bytes);
            if(readLength < len){
                throw new IOException(String.format("File length is [%s] but read [%s]!", len, readLength));
            }
        } catch (Exception e){
            throw new IoCommonException(e);
        }

        return bytes;
    }

    /**
     * ZIP文件流解压
     *
     * @param res        输入流
     * @param targetPath 目标路径
     * @param charset    字符集
     * @return boolean
     * @author yuhh
     * @date 2024-01-25 17:09:18
     */
    public static boolean unzipInputStream(InputStream res, String targetPath, String charset) {
        File distFile =  new File(targetPath);
        if(!distFile.exists()){
            if (!distFile.mkdirs()){
                return false;
            }
        }
        try (ZipInputStream zip = new ZipInputStream(res, Charset.forName(charset))) {
            ZipEntry entry;
            while ((entry = zip.getNextEntry()) != null) {
                String fileName = entry.getName();
                File file = new File(targetPath + "\\" + fileName);
                if (fileName.endsWith("/")) {
                    return file.mkdir();
                } else {
                    try(BufferedOutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(file.toPath()))){
                        // 字符缓冲区
                        byte[] buf = new byte[1024];
                        int len;
                        while ((len = zip.read(buf, 0, buf.length)) > 0) {
                            outputStream.write(buf, 0, len);
                        }
                    } catch (IOException e) {
                        logger.error("ZIP文件流解压出现异常！", e);
                        return false;
                    }
                }
            }
            return true;
        } catch (Exception e) {
            logger.error("zip文件流解压出现异常！", e);
        }
        return false;
    }

    /**
     * 保存文件
     *
     * @param file     需要保存的文件
     * @param path     保存的路径
     * @param fileName 文件名
     * @return {@link String }
     * @author yuhh
     * @date 2024-03-19 16:29:53
     */
    public static String saveMultipartFile(MultipartFile file, String path, String fileName){
        // 确保目录存在
        File directory = new File(path);
        if (!directory.exists()) {
            if (!directory.mkdirs()){
                logger.info("保存文件时创建文件夹失败");
                return "";
            }
        }
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        String prefix = fileName.substring(0, fileName.indexOf("."));
        fileName = prefix + LocalDateUtil.getFormatDate(new Date(), LocalDateUtil.DATE_TIME_FORMAT_UNSIGNED) + suffix;
        String realPath = path + File.separator + fileName;
        // 保存文件
        Path filePath = Paths.get(realPath);
        try {
            Files.copy(file.getInputStream(), filePath);
            return realPath;
        } catch (IOException e) {
            logger.error("保存文件出现异常，文件目录：{}", realPath, e);
            return "";
        }
    }

    private FileUtil(){

    }
}
